package processing_model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import data_generator.entity.SensorNode;
import data_generator.entity.Temperature;
import data_generator.xml.XMLConfig;

import processing.core.*;
public class Paint2D extends PApplet{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	final int ROW_OFFSET = 150;
	final int COLUMN_OFFSET = 150;
	//ArrayList<Point> entries;
	final int MAX_RADIUS = 150;
	int [][] direction = new int[][]{{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
	final int AREA_RANGE = 301;
	boolean [][] area = new boolean[AREA_RANGE][AREA_RANGE];
	int radius;
	PImage[] img_floor = new PImage[3];
	boolean f;
	ArrayList<boolean[][]> mapList;
	final int MAP_WIDTH = 802;
	final int MAP_HEIGHT = 720;
	boolean [][] map_temp;
	int currentMapIndex = 0;
	//test
	ArrayList<ArrayList<SensorNode>> sensorNodes;
	//ArrayList<NodePaintingInfo> paintInfos = new ArrayList<NodePaintingInfo>();
	ArrayList<Entry> sensors = new ArrayList<Entry>();
	int sensorIndex = 0;
	PImage image_temp = createImage(AREA_RANGE, AREA_RANGE,ARGB);
	Map<SensorNode, NodePaintingInfo> paintInfos = new HashMap<SensorNode, NodePaintingInfo>();
	public void setup(){
		//
		NodePaintingInfo nodePaintingInfo_temp;
		Entry entry_temp;
		sensorNodes = new ArrayList<ArrayList<SensorNode>>();
		sensorNodes.add(new ArrayList<SensorNode>());
		sensorNodes.add(new ArrayList<SensorNode>());
		@SuppressWarnings("rawtypes")
		Iterator iterator = XMLConfig.nodeMap.keySet().iterator();
		while(iterator.hasNext()){
				SensorNode sn = (SensorNode) iterator.next();
				if(sn.getLocation().getZ() == 1)
				{
					sensorNodes.get(0).add(sn);
				}
				else {
					sensorNodes.get(1).add(sn);
				}
			
		}
	  size(MAP_WIDTH,MAP_HEIGHT);
	  img_floor[0] = loadImage("./images/floor1_t.png");
	  img_floor[1] = loadImage("./images/floor2_t.png");
	  //img_floor[2] = loadImage("floor3_t.png");

	  f = false;
	  mapList = new ArrayList<boolean[][]>();
	  for(int k = 0;k<2;k++)
	  {
		  map_temp = new boolean[MAP_WIDTH][MAP_HEIGHT];
		  img_floor[k].loadPixels();
		  for(int i =0;i<MAP_WIDTH;i++)
			  for(int j =0;j<MAP_HEIGHT;j++)
			  {
				  int location = i+j*MAP_WIDTH;
				  float red = red(img_floor[k].pixels[location]);
				  float blue = blue(img_floor[k].pixels[location]);
				  float green = green(img_floor[k].pixels[location]);
				  if(red == 0&&blue == 0 && green == 0)
				  {
					  map_temp[i][j] = false;  
				  }
				  else {
					  map_temp[i][j] = true;
				  }
			  }
		  mapList.add(map_temp);
	  }
	  for(int i=0;i<2;i++)
	  {
		  ArrayList<SensorNode> sensornodeList = sensorNodes.get(i);
		  for(int j=0;j<sensornodeList.size();j++)
		  {
			  SensorNode sn = sensornodeList.get(j);
			  nodePaintingInfo_temp = new NodePaintingInfo();
			  entry_temp = new Entry(sn.getLocation().getX(), sn.getLocation().getY(), 0);
			  bfs(entry_temp, nodePaintingInfo_temp, i);
			  paintInfos.put(sn, nodePaintingInfo_temp);
		  }
	  }

	  colorMode(HSB,360,100,100);
	}
	public void firstDraw()
	{
		for(int i=0;i<2;i++)
		{
			background(0,0,100);
			image(img_floor[i],0,0);
			String filename = "./images/dst_floor"+i+".png";
			save(filename);
		}
	}
	public void draw(Map<SensorNode, Temperature> sensorInfos)
	{
		for(int i=0;i<2;i++)
		{
			background(0,0,100);
			ArrayList<SensorNode> sensorList = sensorNodes.get(i);
			for(int j=0;j<sensorList.size();j++)
			{
				SensorNode sn = sensorList.get(j);
				if(!sensorInfos.containsKey(sn))
					continue;
				Temperature temperature = sensorInfos.get(sn);
				float hue = map(temperature.getTemperature(), 5, 25, 230, 360);
				drawTemperature(paintInfos.get(sn),hue);
			}
			image(img_floor[i],0,0);
			String filename = "./images/dst_floor"+i+".png";
			save(filename);
		}

		 
	}
	int searchPosition(int start_index, float dist,NodePaintingInfo nodePaintingInfo)
	{
		for(int i=start_index;i<nodePaintingInfo.entries.size();i++)
		{
			Entry entry = nodePaintingInfo.entries.get(i);
			if(entry.dist > dist)
				return i;
		}
		return nodePaintingInfo.entries.size();
	}
	void bfs(Entry center,NodePaintingInfo nodePaintingInfo,int currentMapIndex)
	{
		int index = -1;
		int InsertIndex = 0;
		float increasement;
		for(int i=0;i<AREA_RANGE;i++)
			  for(int j=0;j<AREA_RANGE;j++)
			  {
				  area[i][j] = false;
			  }
		area[ROW_OFFSET][COLUMN_OFFSET] = true;
		nodePaintingInfo.entries.add(center);
		while(index<nodePaintingInfo.entries.size()-1)
		{
			index++;
			Entry entry = nodePaintingInfo.entries.get(index);
			if(entry.dist >= MAX_RADIUS)
			{
				break;
			}
			for(int i =0;i<8;i++)
			{
				//test map boundary
				if(entry.x+direction[i][0]<0||entry.x+direction[i][0]>=MAP_WIDTH)
					continue;
				if(entry.y+direction[i][1]<0||entry.y+direction[i][1]>=MAP_HEIGHT)
					continue;
				//test area boundary
				if(entry.x+direction[i][0]-center.x+ROW_OFFSET<0||entry.x+direction[i][0]-center.x+ROW_OFFSET>=AREA_RANGE)
					continue;
				if(entry.y+direction[i][1] - center.y+COLUMN_OFFSET<0||entry.y+direction[i][1] - center.y+COLUMN_OFFSET>=AREA_RANGE)
					continue;
				//test travelled
				if(area[entry.x+direction[i][0]-center.x+ROW_OFFSET][entry.y+direction[i][1] - center.y+COLUMN_OFFSET])
					continue;
				//test wall
				if(mapList.get(currentMapIndex)[entry.x+direction[i][0]][entry.y+direction[i][1]]==false)
				{
					if(entry.dist + 75 <=MAX_RADIUS)
					{
						Entry entry_new = new Entry(entry.x+direction[i][0], entry.y+direction[i][1],entry.dist+75);
						area[entry_new.x-center.x+ROW_OFFSET][entry_new.y - center.y+COLUMN_OFFSET] = true;
						nodePaintingInfo.entries.add(entry_new);
					}
					continue;
				}
				if(i>=4)
					increasement = (float) 1.414;
				else 
					increasement = 1;
				InsertIndex = searchPosition(index, entry.dist+increasement,nodePaintingInfo);
				Entry entry_new = new Entry(entry.x+direction[i][0], entry.y+direction[i][1],entry.dist+increasement);
				area[entry_new.x-center.x+ROW_OFFSET][entry_new.y - center.y+COLUMN_OFFSET] = true; 
	
				nodePaintingInfo.entries.add(InsertIndex,entry_new);
			}
		}
	}
	void drawTemperature(NodePaintingInfo nodePaintingInfo,float hue_value)
	{
		float preDist = -1;
		float dist;
		float transparent = 255;
		//float hue_value = random(180,360);
		Entry center = nodePaintingInfo.entries.get(0);
		image_temp.loadPixels();
		for(int i=0;i<AREA_RANGE;i++)
			for(int j=0;j<AREA_RANGE;j++)
				image_temp.pixels[i+j*AREA_RANGE] = 16777215;
		for(int i=0;i<nodePaintingInfo.entries.size();i++)
		{
			Entry entry = nodePaintingInfo.entries.get(i);
			dist = entry.dist;
			if(dist!=preDist)
			{
				transparent = map((float)Math.pow(MAX_RADIUS-dist,1.25), 0, (float)Math.pow(MAX_RADIUS, 1.25), 0, 255);
			}
			int location = entry.x - center.x + ROW_OFFSET + (entry.y - center.y + COLUMN_OFFSET)*AREA_RANGE;
			image_temp.pixels[location] = color(hue_value,100,100,transparent);
			preDist = dist;
		}

		image_temp.updatePixels();
		image(image_temp, center.x - ROW_OFFSET, center.y - COLUMN_OFFSET);
		
	}

	

	 
}
